#include "PGE2D.h"
#include <cstdlib>
#include <ctime>
#include <sstream>
#include <cassert>

PGE2D::Engine::Engine()
{
	srand( (unsigned int)time( nullptr ) );
	p_versionMajor = VERSION_MAJOR;
	p_versionMinor = VERSION_MINOR;
	p_revision = VERSION_REVISION;

	p_appTitle = getVersionText();
	p_screenWidth = 640;
	p_screenHeight = 480;
	p_colorDepth = 32;

	p_fullScreen = false;
	p_pauseMode = false;

	p_ambientColor = D3DCOLOR_RGBA( 255, 255, 255, 0 );
	p_windowHandle = 0;

	p_frameCount_core = 0;
	p_frameRate_core = 0;
	p_frameCount_real = 0;
	p_frameRate_real = 0;
	p_maximizeProcessor = false;
}

PGE2D::Engine::~Engine()
{
	if( p_device ) p_device->Release();
	if( p_d3d ) p_d3d->Release();
}

int PGE2D::Engine::Init(int width, int height, int colorDepth, bool fullScreen) 
{
	p_d3d = Direct3DCreate9( D3D_SDK_VERSION );
	if( !p_d3d )
		return 0;

	D3DDISPLAYMODE dm;
	p_d3d->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &dm );

	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory( &d3dpp, sizeof( d3dpp ) );
	d3dpp.Windowed = ( !fullScreen );
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.EnableAutoDepthStencil = true;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
	d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
	d3dpp.BackBufferFormat = dm.Format;
	d3dpp.BackBufferCount = 1;
	d3dpp.BackBufferWidth = width;
	d3dpp.BackBufferHeight = height;
	d3dpp.hDeviceWindow = p_windowHandle;

	p_d3d->CreateDevice(
		D3DADAPTER_DEFAULT,
		D3DDEVTYPE_HAL,
		p_windowHandle,
		D3DCREATE_HARDWARE_VERTEXPROCESSING,
		&d3dpp,
		&p_device);

	if( !p_device ) return 0;

	ClearScene( D3DCOLOR_XRGB( 0,0,0 ) );

	p_device->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &p_backbuffer );

	p_device->SetRenderState( D3DRS_ZENABLE, true );
	p_device->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
	SetAmbient( p_ambientColor );

	HRESULT result = D3DXCreateSprite( p_device, &p_sprite_handler );
	if (result != D3D_OK) return 0;

	if( !PGE2D::game_init( getWindowHandle() ) ) return 0;
	SetDefaultMaterial();

	return true; 
}

void PGE2D::Engine::Close() { PGE2D::game_end(); }

void PGE2D::Engine::Update() 
{
	static Timer timedUpdate;

	p_frameCount_core++;
	if( p_coreTimer.stopwatch( 999 ) ) {
		p_frameRate_core = p_frameCount_core;
		p_frameCount_core = 0;
	}

	game_update();

	if( !timedUpdate.stopwatch( 14 ) ) {
		if( !getMaximizeProcessor() )
			Sleep(1);
	}
	else
		p_frameCount_real++;
	if( p_realTimer.stopwatch( 999 ) ) {
		p_frameRate_real = p_frameCount_real;
		p_frameCount_real = 0;
	}

	RenderStart();

	PGE2D::game_render3d();

	RenderStop();
}
void PGE2D::Engine::Shutdown() { PGE2D::gameover = true; }

std::string PGE2D::Engine::getVersionText()
{
	std::ostringstream s;
	s << "PGE2D v" << p_versionMajor << "." << p_versionMinor << "." << p_revision;
	return s.str();
}

void PGE2D::Engine::ClearScene(D3DCOLOR color)
{
	p_device->Clear( 0, nullptr, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, color, 1.0f, 0 );
}

void PGE2D::Engine::SetDefaultMaterial()
{
	D3DMATERIAL9 mat;
	memset( &mat, 0, sizeof(mat) );
	mat.Diffuse.r = 1.0f;
	mat.Diffuse.g = 1.0f;
	mat.Diffuse.b = 1.0f;
	mat.Diffuse.a = 1.0f;
	p_device->SetMaterial( &mat );
}

void PGE2D::Engine::SetAmbient( D3DCOLOR colorValue )
{
	p_ambientColor = colorValue;
	p_device->SetRenderState( D3DRS_AMBIENT, p_ambientColor );
}

int PGE2D::Engine::RenderStart()
{
	assert( p_device );
	if ( p_device->BeginScene() != D3D_OK ) return 0;
	return 1;
}

int PGE2D::Engine::RenderStop()
{
	assert( p_device );
	if( p_device->EndScene() != D3D_OK ) return 0;
	if( p_device->Present( nullptr, nullptr, nullptr, nullptr ) != D3D_OK ) return 0;
	return 1;
}

void PGE2D::Engine::SetIdentity()
{
	D3DXMATRIX matrixWorld;
	D3DXMatrixIdentity(&matrixWorld);
	g_engine->getDevice()->SetTransform(D3DTS_WORLD, &matrixWorld);
}
